
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing;



namespace EForms
{
	
	/// <summary>
	/// GraphicsHelper
	/// </summary>
	public class GraphicsHelper
	{
		/// <summary>
		/// Constructor
		/// </summary>
		public GraphicsHelper(Control control)
		{
		}
		#region printing richTextBox
		/// <summary>
		/// Convert between 1/100 inch (unit used by the .NET framework)
		/// and twips (1/1440 inch, used by Win32 API calls)
		/// </summary>
		/// <param name="n">Value in 1/100 inch</param>
		/// <returns>Value in twips</returns>
		private static int HundredthInchToTwips(int n)
		{
			return (int)(n*14.4);
		}

		/// <summary>
		/// Calculate (and render) the contents of the RichTextBox for a printing page
		/// </summary>
		/// <param name="handle">handle of printed control</param>
		/// <param name="measureOnly">If true, only the calculation is performed, otherwise the text is rendered as well</param>
		/// <param name="e">The PrintPageEventArgs object from the PrintPage event</param>
		/// <param name="charFrom">Index of first character to be printed</param>
		/// <param name="charTo">Index of last character to be printed</param>
		/// <returns>(Index of last character that fitted on the page) + 1</returns>
		private static int FormatRange(IntPtr handle, bool measureOnly, System.Drawing.Printing.PrintPageEventArgs e, int charFrom, int charTo)
		{
			CUtil.Win32.User32.CHARRANGE cr;
			cr.cpMin=charFrom;
			cr.cpMax=charTo;

			CUtil.Win32.User32.RECT rc;
			rc.top		= HundredthInchToTwips(e.MarginBounds.Top);
			rc.bottom	= HundredthInchToTwips(e.MarginBounds.Bottom);
			rc.left		= HundredthInchToTwips(e.MarginBounds.Left);
			rc.right	= HundredthInchToTwips(e.MarginBounds.Right);

			CUtil.Win32.User32.RECT rcPage;
			rcPage.top		= HundredthInchToTwips(e.PageBounds.Top);
			rcPage.bottom	= HundredthInchToTwips(e.PageBounds.Bottom);
			rcPage.left		= HundredthInchToTwips(e.PageBounds.Left);
			rcPage.right	= HundredthInchToTwips(e.PageBounds.Right);

			IntPtr hdc = e.Graphics.GetHdc();

			CUtil.Win32.User32.FORMATRANGE fr;
			fr.chrg		 = cr;
			fr.hdc		 = hdc;
			fr.hdcTarget = hdc;
			fr.rc		 = rc;
			fr.rcPage	 = rcPage;

			IntPtr res;

			IntPtr wpar = new IntPtr(measureOnly ? 0 : 1);
			IntPtr lpar = Marshal.AllocCoTaskMem( Marshal.SizeOf( fr ) ); 
			Marshal.StructureToPtr(fr, lpar, false);

			res = CUtil.Win32.User32.SendMessage(handle, CUtil.Win32.User32.EM_FORMATRANGE, wpar, lpar);

			Marshal.FreeCoTaskMem(lpar);

			e.Graphics.ReleaseHdc(hdc);

			return res.ToInt32();
		}
		/// <summary>
		/// Needs to be called after the print job is finished to release cached information
		/// </summary>
		/// <param name="handle">handle of printed control</param>
		private static void FormatRangeDone(IntPtr handle)
		{
			IntPtr wpar = new IntPtr(0);
			IntPtr lpar = new IntPtr(0);
			CUtil.Win32.User32.SendMessage(handle, CUtil.Win32.User32.EM_FORMATRANGE, wpar, lpar);
		}
		#endregion

		/// <summary>
		/// GetBitmapFromControl
		/// </summary>
		/// <param name="controlHolder">
		/// Parent control
		/// </param>
		/// <param name="c">
		/// source control for imaging.
		/// </param>
		/// <param name="isVisible">
		/// if the control currently visable, if Yes
		/// no parent form for control is created, No
		/// independent form is created for hosting the
		/// control and this form is immediately destroyed 
		/// after taking the image of control. 
		/// </param>
		/// <returns>
		/// Bitmap of the source control.
		/// </returns>
		public static Bitmap GetBitmapFromControl(Control controlHolder, Control c, bool isVisible)
		{
			Bitmap richTextBoxImage = null;
			Point rtbLocation = Point.Empty;;
			//WorkAround : Fix Later.
			//Bug fix for FormatedTextControl
			foreach (Control subControl in c.Controls)
			{
				if (subControl.GetType().Name == "FormattedRichTextBox")
				{
					rtbLocation = subControl.Location;
					richTextBoxImage = new Bitmap(subControl.Width, subControl.Height);
					Graphics g = Graphics.FromImage(richTextBoxImage);
					Rectangle r = subControl.Bounds;
					System.Drawing.Printing.PrintPageEventArgs printArgs = new System.Drawing.Printing.PrintPageEventArgs(g, r, r, null);
					FormatRange(subControl.Handle, false, printArgs, 0, -1);
					// Clean up cached information
					FormatRangeDone(subControl.Handle);
					break;
				}
			}
			Point origControlLoc = Point.Empty;
			//when control is not shown
			//we need to show it for correct imaging
			if (isVisible == false)
			{
				// Prapare Control For Imaging
				if (c.Parent == null && controlHolder != null)
				{
					//show it very far from current view.
					//For getting the correct image of the control
					//we need to have visible control./but we don't want
					//see the control in current view(layout)/
					c.Location = new Point(-10000, -10000);
					controlHolder.Controls.Add(c);
					//take focus from the source control
					//and give it to the parent control.
					//bm97793629: don't modify the focus while copying a control!!!
					//controlHolder.Select();
				}
				else
				{
					//set the original loc so that later 
					//we can recover it.
					origControlLoc = c.Location;
					//show it very far from current view.
					//For getting the correct image of the control
					//we need to have visible control./but we don't want
					//see the control in current view(layout)/
					c.Location = new Point(-10000, -10000);
					c.Visible = true;
				}
			}
			//Image extracting
			//prepare image and graphics.
			Bitmap b = null;
			if (c.Width > 0 && c.Height > 0 )
			{
				b = new Bitmap(c.Size.Width, c.Size.Height);

				Graphics g = Graphics.FromImage(b);
			
				IntPtr h = c.Handle;

				IntPtr phdc = g.GetHdc();

				CUtil.Win32.User32.SendMessage(h, CUtil.Win32.WindowsMessages.WM_PRINT, phdc, 
					(IntPtr) (CUtil.Win32.User32.PrintOptions.PRF_CHILDREN
					| CUtil.Win32.User32.PrintOptions.PRF_CLIENT 
					| CUtil.Win32.User32.PrintOptions.PRF_NONCLIENT )
					);

				g.ReleaseHdc(phdc);

				//Recover the situation bevor extracting the image
				if (origControlLoc != Point.Empty)
				{
					c.Visible = false;
					c.Location = origControlLoc;
				}
				else if (controlHolder.Controls.Contains(c))
				{
					controlHolder.Controls.Remove(c);
				}
				if (b != null && richTextBoxImage != null)
				{
					Graphics gr = Graphics.FromImage(b);
					gr.DrawImage(richTextBoxImage, rtbLocation);
				}
			}
			return b;
		}
		/// <summary>
		/// Extracting the image from the source control
		/// </summary>
		/// <param name="controlHolder">
		/// Parent of source control.
		/// </param>
		/// <param name="c">
		/// source control for imaging.
		/// </param>
		/// <returns></returns>
		public static Bitmap GetBitmapFromControl(Control controlHolder, Control c)
		{
			//we suppose that the control is not visible, but created dynamically
			return GetBitmapFromControl(controlHolder, c, false);
		}
		/// <summary>
		/// Draws the image over control.
		/// </summary>
		/// <param name="c">Control</param>
		/// <param name="b">Bitmap</param>
		/// <param name="x">x location</param>
		/// <param name="y"> y location</param>
		public static void SetBitmapToControl(Control c, Bitmap b, int x, int y)
		{
			Graphics cg = c.CreateGraphics();
			cg.DrawImage(b, x, y, b.Size.Width, b.Size.Height);
		}
		/// <summary>
		/// Draws the image over control.
		/// </summary>
		/// <param name="c"> control </param>
		/// <param name="b"> Bitmap </param>
		public static void SetBitmapToControl(Control c, Bitmap b)
		{
			//we suppose, the image will be positioned top, left
			SetBitmapToControl( c, b, 0, 0);
		}
		/// <summary>
		/// Fits the Bitmap over Form
		/// </summary>
		/// <param name="f"> Form </param>
		/// <param name="b"> Bitmap </param>
		public static void FitBitmapToForm(Form f, Bitmap b)
		{
			FitBitmapToControl((Control)f, b);
		}
		/// <summary>
		/// Fits Bitmap over control so that,
		/// it straches over whole control.
		/// </summary>
		/// <param name="c">
		/// Control 
		/// </param>
		/// <param name="b">
		/// Bitmap
		/// </param>
		public static void FitBitmapToControl(Control c, Bitmap b)
		{
			Graphics cg = c.CreateGraphics();
			// Create rectangle for displaying image.
			Rectangle destRect = new Rectangle(0, 0, c.Width, c.Height);
			// Draw image to screen.
			cg.DrawImage(b, destRect);
			//free resources
			cg.Dispose();
			cg = null;
		}
	}
}
